package com.qp;

import be.ac.ulg.montefiore.run.distributions.GaussianDistribution;
import be.ac.ulg.montefiore.run.jahmm.ObservationReal;
import be.ac.ulg.montefiore.run.jahmm.OpdfGaussian;
import com.utils.SequenceIterator;

import java.util.List;


/**
 * Created with IntelliJ IDEA.
 * User: bigmar
 * Date: 12/6/14
 * Time: 5:19 PM
 * To change this template use File | Settings | File Templates.
 */
public class ContionousOutputDistributionEstimator
{
    private List<OpdfGaussian> gaussianList;
    private double[] mixtureWeights;
    private SequenceIterator sequenceIterator;
    private int numberOfObservations;
    private int numberOfModels;


    public ContionousOutputDistributionEstimator(List<OpdfGaussian> gaussianList, double[] mixtureWeights, SequenceIterator sequenceIterator, int numberOfObservations)
    {
        this.gaussianList=gaussianList;
        this.mixtureWeights=mixtureWeights;
        this.sequenceIterator=sequenceIterator;
        this.numberOfObservations=numberOfObservations;
        numberOfModels=gaussianList.size();
    }
    public double[] estimate()
    {
        ObservationReal prevValue=null;

        double[] retVal=new double[numberOfModels*numberOfModels];
        for (int firstModelIndex=0; firstModelIndex<numberOfModels; ++firstModelIndex)
        {
            for (int secModelIndex=0; secModelIndex<numberOfModels; ++secModelIndex)
            {
                int arrayIndex=firstModelIndex+secModelIndex*numberOfModels;
                sequenceIterator=sequenceIterator.createNewIterator();
                boolean isFirst=true;
                while(sequenceIterator.hasNext())
                {
                    ObservationReal value=((ObservationReal) sequenceIterator.next());
                    if (!isFirst)
                    {
//                        double firstStationaryChain=calcStationaryChain(firstModelIndex, prevValue);
                        double prevProbability=gaussianList.get(secModelIndex).probability(prevValue);
                        double probability=gaussianList.get(firstModelIndex).probability(value);
//                        double secStationaryChain=calcStationaryChain(firstModelIndex, value);

//                        retVal[firstModelIndex][secModelIndex]+=firstStationaryChain*secStationaryChain;
                        retVal[arrayIndex]+=prevProbability*probability;


                    }
                    isFirst=sequenceIterator.isNewSequence();
                    prevValue=value;


                }
                retVal[arrayIndex]/=(numberOfObservations-sequenceIterator.getNumberOfSequences());

            }
        }
        return retVal;
    }
    private double calcStationaryChain(int modelIndex, ObservationReal value)
    {
        double denominator=0;
        for (int i=0; i<gaussianList.size(); ++i)
        {
            OpdfGaussian gaussianDistribution=gaussianList.get(i);
            double mixtureWeight=mixtureWeights[i];
            denominator+=gaussianDistribution.probability(value)*mixtureWeight;
        }
        double nominator=gaussianList.get(modelIndex).probability(value)*mixtureWeights[modelIndex];
        return nominator/denominator;
    }
}
